package com.ruoyi.system.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.ruoyi.common.core.utils.StringUtils;
import com.ruoyi.common.mybatis.core.page.PageQuery;
import com.ruoyi.common.mybatis.core.page.TableDataInfo;
import com.ruoyi.common.satoken.utils.LoginHelper;
import com.ruoyi.system.api.domain.SysDept;
import com.ruoyi.system.api.domain.SysUser;
import com.ruoyi.system.domain.*;
import com.ruoyi.system.domain.bo.InvestigationBo;
import com.ruoyi.system.domain.vo.InvestigationStatisticVo;
import com.ruoyi.system.domain.vo.InvestigationUserAnswerVo;
import com.ruoyi.system.domain.vo.InvestigationVo;
import com.ruoyi.system.enums.MessageTypeEnum;
import com.ruoyi.system.enums.PubStatusEnum;
import com.ruoyi.system.enums.ReadTypeEnum;
import com.ruoyi.system.mapper.*;
import com.ruoyi.system.service.IInvestigationService;
import lombok.RequiredArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.collections4.MapUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 问卷Service业务层处理
 *
 * @author ruoyi
 * @date 2024-12-13
 */
@RequiredArgsConstructor
@Service
public class InvestigationServiceImpl implements IInvestigationService {

    private final InvestigationMapper baseMapper;

    private final InvestigationViewMapper viewMapper;

    private final InvestigationQuestionMapper questionMapper;

    private final InvestigationUserAnswerMapper answerMapper;

    private final SysUserMessageMapper messageMapper;

    private final SysUserMapper userMapper;

    private final SysDeptMapper deptMapper;

    /**
     * 查询问卷
     */
    @Override
    public InvestigationVo queryById(Long id) {
        return queryById(id, false);
    }

    @Override
    public InvestigationVo queryById(Long id, boolean onlyMain) {
        InvestigationVo investigationVo = baseMapper.selectVoById(id);
        if (investigationVo == null) {
            throw new UnsupportedOperationException("问卷不存在");
        }
        if (onlyMain) {
            return investigationVo;
        }

        List<InvestigationQuestion> questions = questionMapper.getByInvestigationId(id);
        investigationVo.setQuestions(questions);
        List<InvestigationUserAnswerVo> answers = answerMapper.getByInvestigationIdAndUserId(id, LoginHelper.getUserId());
        investigationVo.setAnswers(answers);

        InvestigationUserView view = viewMapper.selectByInvestigationAndUser(id, LoginHelper.getUserId());
        if (view == null) {
            view = new InvestigationUserView();
            view.setInvestigationId(id);
            view.setUserId(LoginHelper.getUserId());
            viewMapper.insertOrUpdate(view);
        }

        return investigationVo;
    }

    /**
     * 查询问卷列表
     */
    @Override
    public TableDataInfo<InvestigationVo> queryPageList(InvestigationBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<Investigation> lqw = buildQueryWrapper(bo);
        Page<InvestigationVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询问卷列表
     */
    @Override
    public List<InvestigationVo> queryList(InvestigationBo bo) {
        LambdaQueryWrapper<Investigation> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<Investigation> buildQueryWrapper(InvestigationBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<Investigation> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getType() != null, Investigation::getType, bo.getType());
        lqw.like(StringUtils.isNotBlank(bo.getName()), Investigation::getName, bo.getName());
        lqw.eq(bo.getPubStatus() != null, Investigation::getPubStatus, bo.getPubStatus());
        lqw.gt(bo.getAnswerCount() != null && bo.getAnswerCount() > 0, Investigation::getAnswerCount, 0);
        lqw.eq(bo.getAnswerCount() != null && bo.getAnswerCount() == 0, Investigation::getAnswerCount, 0);
        if (StringUtils.isNotBlank(bo.getStartDate())) {
            lqw.ge(true, Investigation::getCreateTime, bo.getStartDate() + " 00:00:00");
        }
        if (StringUtils.isNotBlank(bo.getEndDate())) {
            lqw.le(true, Investigation::getCreateTime, bo.getEndDate() + " 23:59:59");
        }
        return lqw;
    }

    /**
     * 新增问卷
     */
    @Override
    @Transactional
    public Boolean insertByBo(InvestigationBo bo) {
        Investigation add = BeanUtil.toBean(bo, Investigation.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        List<InvestigationQuestion> questions = bo.getQuestions();
        questions.forEach(question -> {
            question.setInvestigationId(add.getId());
        });
        questionMapper.insertBatch(questions);
        return flag;
    }

    /**
     * 修改问卷
     */
    @Override
    @Transactional
    public Boolean updateByBo(InvestigationBo bo) {
        Investigation update = BeanUtil.toBean(bo, Investigation.class);
        validEntityBeforeSave(update);

        questionMapper.deleteByInvestigationId(bo.getId());
        List<InvestigationQuestion> questions = bo.getQuestions();
        questions.forEach(question -> {
            question.setInvestigationId(bo.getId());
        });
        questionMapper.insertBatch(questions);

        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(Investigation entity) {
        //TODO 做一些数据校验,如唯一约束
        entity.setPubStatus(PubStatusEnum.NOT_PUBLISH.getValue());
    }

    /**
     * 批量删除问卷
     */
    @Override
    @Transactional
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if (isValid) {
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        questionMapper.deleteByInvestigationIds(ids);
        return baseMapper.deleteBatchIds(ids) > 0;
    }

    @Override
    public void incAnswerCount(Long investigationId) {
        baseMapper.incAnswerCount(investigationId);
    }

    @Override
    public boolean updateStatus(Long investigationId, Integer status) {
        baseMapper.updateStatus(investigationId, status);
        if (PubStatusEnum.PUBLISHED.getValue().equals(status)) {
            messageMapper.deleteByInvestigationId(investigationId);
            List<SysUserMessage> messages = getInvestigationMessages(investigationId);
            if (CollectionUtils.isNotEmpty(messages)) {
                messageMapper.insertBatch(messages);
            }
        }
        return true;
    }

    private List<SysUserMessage> getInvestigationMessages(Long investigationId) {
        List<SysUser> students = userMapper.getUserListByRoleId(2);
        if (CollectionUtils.isEmpty(students)) {
            return null;
        }
        SysUser sender = userMapper.selectUserById(LoginHelper.getUserId());
        List<SysUserMessage> messages = new ArrayList<>(students.size());
        for (SysUser student : students) {
            SysUserMessage msg = new SysUserMessage();
            msg.setReceiver(student.getUserId());
            msg.setMsgType(MessageTypeEnum.INVESTIGATION.getValue());
            msg.setContent(investigationId.toString());
            msg.setSender(sender.getUserId());
            msg.setSenderName(sender.getNickName());
            msg.setTitle(msg.getSenderName() + "邀请你回答问卷");
            msg.setIsRead(ReadTypeEnum.UN_READ.getValue());
            messages.add(msg);
        }
        return messages;
    }

    @Override
    public InvestigationStatisticVo statistic(Long id) {
        InvestigationStatisticVo statistic = new InvestigationStatisticVo();
        InvestigationVo investigationVo = baseMapper.selectVoById(id);
        if (investigationVo == null) {
            throw new UnsupportedOperationException("问卷不存在");
        }
        List<InvestigationQuestion> questions = questionMapper.getByInvestigationId(id);
        investigationVo.setQuestions(questions);
        statistic.setInvestigation(investigationVo);
        if (investigationVo.getPubTime() != null) {
            statistic.setPubDuration((System.currentTimeMillis() - investigationVo.getPubTime().getTime()) / 1000);
        }
        LambdaQueryWrapper<InvestigationUserView> view = Wrappers.lambdaQuery();
        view.eq(true, InvestigationUserView::getInvestigationId, id);
        statistic.setViewUv(viewMapper.selectCount(view));
        LambdaQueryWrapper<InvestigationUserAnswer> answerWrapper = Wrappers.lambdaQuery();
        answerWrapper.eq(true, InvestigationUserAnswer::getInvestigationId, id);
        statistic.setAnswerUv(answerMapper.selectCount(answerWrapper));

        if (statistic.getAnswerUv() > 0) {
            List<Map> answerStatic = answerMapper.getStatic(id);
            if (CollectionUtils.isNotEmpty(answerStatic)) {
                Map<Long, Map> questionStatic = new HashMap<>();
                for (Map map : answerStatic) {
                    Long questionId = Long.valueOf(map.get("questionId").toString());
                    Object answer = map.get("answer");
                    Long uv = Long.valueOf(map.get("uv").toString());
                    Map qs = questionStatic.get(questionId);
                    if (qs == null) {
                        qs = new HashMap<>();
                        questionStatic.put(questionId, qs);
                    }
                    qs.put(answer, uv);
                }
                statistic.setStatistic(questionStatic);
            }
        }

        return statistic;
    }

    @Override
    public List getAnswerExport(InvestigationVo investigation) {
        List<InvestigationQuestion> questions = questionMapper.getByInvestigationId(investigation.getId());
        if (CollectionUtils.isEmpty(questions)) {
            throw new UnsupportedOperationException("问卷题目不存在");
        }
        List list = new ArrayList();
        List title = getAnswerExportTitle(questions);
        list.add(title);

        getAnswerExportList(investigation, questions, list);
        return list;
    }

    private List getAnswerExportTitle(List<InvestigationQuestion> questions) {
        List title = new ArrayList();
        title.add("提交时间");
        title.add("用户名");
        title.add("组织");
        questions.sort(Comparator.comparing(InvestigationQuestion::getQuestionOrder));
        for (InvestigationQuestion question : questions) {
            title.add(question.getName());
        }

        return title;
    }

    private void getAnswerExportList(InvestigationVo investigation, List<InvestigationQuestion> questions, List list) {
        List<InvestigationUserAnswerVo> answers = answerMapper.getByInvestigationId(investigation.getId());
        if (CollectionUtils.isEmpty(answers)) {
            return;
        }
        Map<Long, List<InvestigationUserAnswerVo>> userAnswer = answers.stream().collect(Collectors.groupingBy(a -> a.getUserId()));

        Set<Long> userIds = userAnswer.keySet();
        List<SysUser> users = userMapper.selectVoBatchIds(userIds);
        Map<Long, SysUser> userMap = users.stream().collect(Collectors.toMap(u -> u.getUserId(), u -> u));
        List<Long> deptIds = users.stream().map(SysUser::getDeptId).distinct().collect(Collectors.toList());
        List<SysDept> depts = deptMapper.selectVoBatchIds(deptIds);
        Map<Long, String> deptMap = depts.stream().collect(Collectors.toMap(d -> d.getDeptId(), d -> d.getDeptName()));
        for (Map.Entry<Long, List<InvestigationUserAnswerVo>> entry : userAnswer.entrySet()) {
            Long userId = entry.getKey();
            List<InvestigationUserAnswerVo> userAnswers = entry.getValue();
            SysUser user = userMap.get(userId);
            String deptName = deptMap.get(user.getDeptId());
            List tmp = new ArrayList();

            tmp.add(DateUtil.formatDateTime(answers.get(0).getCreateTime()));
            tmp.add(user.getUserName());
            tmp.add(deptName);
            Map<Long, InvestigationUserAnswerVo> answerMap = userAnswers.stream().collect(Collectors.toMap(a -> a.getQuestionId(), a -> a));
            for (InvestigationQuestion question : questions) {
                if (answerMap.containsKey(question.getId())) {
                    tmp.add(answerMap.get(question.getId()).getAnswer());
                } else {
                    tmp.add("");
                }
            }
            list.add(tmp);
        }
    }
}
